BearZPY Blog

Hi, nice to meet you

BearZPY's avatar BearZPY

Gradle 基础介绍

Gradle

本篇文章主要讲述 Gradle 的基本知识点,帮助大家了解 Gradle。

Gradle 背景知识

先介绍概念:

Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具。它使用一种基于 Groovy 的特定领域语言来声明项目设置,而不是传统的 XML 。

这个概念我们先不用去理解,只要知道 Gradle 是一个自动化构建工具就可以了。那么为什么我们在开发 Android 程序的时候需要去使用自动化构建工具呢?答案很简单,就是构建一个 Android 工程需要做很多重复性很高的事情,手动干这些事麻烦又浪费时间,所以我们选择让机器去做。好吧,我承认就是懒,聪明的开发者都愿意找一个正确,高效又能偷懒的方法。

Gradle 是 Google I/O 2013 大会上发布的,用来替换 Ant 和 Maven 的新工具,替换旧工具的原因当然是它们不能让开发者继续开心的懒下去了。

简单讲一下 Ant,Maven 和 Gradle 的关系,这是个题外话。Ant 可以自动化打包,但是许多东西要手动下载添加。Maven 既可以自动化打包,也能帮下载你需要的东西,但是它的逻辑策略写起来很麻烦。两个工具都不大好用,为了能开心的偷懒,Gradle 应运而生。Gradle 集成了上面的功能,非常方别开发使用,但由于某些网络问题,导致初学者使用起来体验并不好。

Gradle 文件结构

Android Studio 创建 Android 工程的时候会创建许多文件,这让不熟悉的人分不清楚不同文件的意义,这里我们先介绍一个最简单的 Gradle 结构,如下图。

gradle_mimi_unit

这个结构一共有 5 个文件。其中 build.gradle 是我们需要编写的 Gradle 的脚本文件,另外四个文件组成了一个 Gradle 中的重要结构:Gradle Wrapper(Gradle 封装器)。

Gradle Wrapper

不同的开发者可能使用不同版本的 Gradle 来构建 Android 项目,多人开发的时候使用不同版本的构建工具,可能出现莫名其妙的问题。大家也都遇到过某个软件在这个电脑上没问题,在另外的电脑上有问题的情况吧。Gradle 封装器就是用来解决这个问题的,每一个封装器都绑定了一个特定版本的 Gradle,当你运行 Gradle 命令的时候,它会先下载相应的 Gradle 版本,并使用这个版本来执行构建,这样就避免了环境不统一的问题。这是个很棒的功能,但由于某些网络问题,下载会超时,导致了很多新手都栽在了这里。这里就不讲述怎么下 Gradle 了,网上很多这方面的资料。

为了完整起见,不要删除 Gradle 封装器里的文件或改变目录结构,这里介绍一下封装器里文件的功能

  • gradlew (Unix Shell 脚本)
  • gradlew.bat (Windows 批处理文件)
  • gradle/wrapper/gradle-wrapper.jar (Jar 包)
  • gradle/wrapper/gradle-wrapper.properties (封装器属性)

Gradle 版本会被下载到用户目录下的 .gradle/wrapper/dists 中。
查看 gradle-wrapper.properties 文件可以看到当前封装器使用的 gradle 版本号。

gradle_wrapper_properties

Unix Shell 环境下使用 gradlew 命令
unix_shell

Windows 环境下使用 gradlew.bat 命令
windows_cmd

build.gradle

build.gradle 是构建所需要的脚本文件,这里给一个最简单的示例。

新建了一个名为 hello 的任务,输出 Hello World。

task hello {
    println "Hello World!"
}

执行 gradlew.bat hello 就能看见 Hello World 输出在控制台上了。

task_hello

Android Studio 里的 Gradle

这里新建一个空的工程,来介绍 Gradle 的作用。

工程目录

Android Studio 是按项目建立的,项目里面可以有不同的 app 模块,简单的说一个项目可以编出几个不同的 app 软件。

项目目录界面如下
android_project

下面介绍目录中 build.gradle 和 Gradle 封装器之外的部分。

  • .gradle 文件夹下放的是 Gradle 构建时的记录信息,无需关心
  • .idea 是 Android Studio 工程记录信息,无需关心
  • app 存放对于的模块文件,这里就是我们开发的app
  • build 存放的是 Gradle 在构建项目的时候生产的文件
  • .gitignore 是版本控制忽略文件,和 Gradle 无关
  • MyApplication.iml 生成文件,无需关心
  • local.properties 存放的 SDK,NDK 在本机上的目录
  • gradle.properties 存放的是整个项目 Gradle 的配置文件
  • settings.gradle 存放的是这个项目包括那些模块,当前只包括一个 app 模块

项目构建脚本

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {  // 配置构建脚本
    repositories {  // 添加远程依赖库
        jcenter()  // JCenter 仓库
    }
    dependencies { // 配置构建依赖插件
        // 声明了一个 构建 Android 的 Gradle 插件
        // Gradle 本身是构建不了 Android 的
        classpath 'com.android.tools.build:gradle:2.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects { // 配置整个项目
    // Android 开发经常需要用一些支持库,这些支持库都有专门的网路存放地,供开发中下载
    repositories { // 添加远程依赖库
        jcenter() // JCenter 仓库
    }
}

task clean(type: Delete) {  // clean 任务清理构建生成的文件
    delete rootProject.buildDir  // 删除 build 文件夹
}

模块目录

android_module

  • build 存放着编译生成的文件
  • libs 放的是模块编译需要使用的库文件
  • src 放着源码和资源文件
  • .gitignore 是版本控制忽略文件,和 Gradle 无关
  • app.iml 生成文件,无需关心
  • build.gradle 是模块构建脚本
  • proguard-rules.pro 是模块混淆规则,防止 app 被破解的

模块构建脚本

apply plugin: 'com.android.application'  // 标明这个脚本是编译 android 应用程序用的

android {  // 编译 apk 文件配置
    compileSdkVersion 25  // SDK 版本号 API 25
    buildToolsVersion "25.0.2" // 使用的编译工具的版本号
    defaultConfig {
        applicationId "com.io.bearzpy.myapplication" // 表明 APP 在系统中的唯一 ID
        minSdkVersion 19  // 兼顾最老的系统版本
        targetSdkVersion 25 // 经过充分测试的版本
        versionCode 1  // 代码版本给系统实际区分不同版本
        versionName "1.0" // 版本名字给人区分不同版本
        // 使用单元测试框架
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes { // 构建变量
        release { // 发布版本
            // 这一部分是防止应用被人破解的
            minifyEnabled false // 控制是否运行混淆的
            // 混淆规则设置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies { // 添加依赖
    // 导入 libs 文件夹下所有的 jar 包
    compile fileTree(dir: 'libs', include: ['*.jar'])
    // 测试应用接口的依赖
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    // 兼容低版本系统的依赖
    compile 'com.android.support:appcompat-v7:25.2.0'
    // 单元测试的依赖
    testCompile 'junit:junit:4.12'
}

依赖库管理

开发者经常会使用一些已有的现成的,可以直接拿来用的解决方案,这极大的提高了开发效率,也着实让他们能够偷懒了,但是这也造成了一些问题。比如当你同时使用这个两个方案解决不同的事情,这两个方案共用了同一个依赖库,但是却使用了不同的版本,这会为我们的程序带来意外的问题。Gradle 拥有解决依赖冲突的能力,它可以自动下载使用合适的版本,尽量帮开发者解决依赖库冲突问题,如果它解决不了,也会报个错给你。

编译不同的 app 版本

实际开发中,开发者往往要准备好几个版本,比如调试版本,发布版本,不同手机厂商使用的版本,都考开发者手动准备也是很费力且容易出错的。Gradle 也提供了构建多版本的功能。例如,模块构建脚本中的构建变量增加了 release 版本,我们可以在 Android Studio 的 Build Variants 里面选则 release 版本,再次编译生成的就是 release 版本了。同理,我们也可以在构建脚本中添加其他的版本,比如付费版本和免费版本等等。

release

Gradle 是怎么工作的

每一个 Gradle 需要完成的工作都是一个任务,这些任务之间有着先后顺序,相互依赖的关系,而 Android 应用程序的构建需要许多这样的任务。Android Studio 有 Gradle 的控制面板可以查看当前项目有哪些任务。

这是一个空的项目所拥有的任务,可以看到项目本身有相当多的任务,对应的模块还有相当多的任务。
gradle_contol

选择一个任务双击可以运行,这里以 build 为例,Run 面板中可以看到所有被执行的任务:
build_task

小结

每当我们修改完程序之后都需要进行编译,然而编译需要这么多的步骤,如果每次都要手动去进行编译,即使能保证人工不出错,所耗费的时间也相当的大,所以有了自动化构建工具。我们在 Android Studio 中点一个 Run 就能完成的工作,实际上由自动化构建工具帮我们处理很多重复的劳动。而当旧的自动化构建工具不能满足我们的需求时,必然会有开发者去更新自动化构建工具,这也是 Android Studio 和 Gradle 成为 Android 开发使用的主流工具的原因。